source('../env.R')

Generate Worldwide Distributions for all Columbidae

Read in the Birdlife Distribution

Birdlife dataset “Bird Species Distribution Maps of the World.” (2020).

A download of the birdlife distributions can be requested from here: https://datazone.birdlife.org/species/requestdis

BIRDLIFE_DISTRIBUTIONS = '/Users/james/Dropbox/PhD/BirdLife/Distribution/SppDataRequest_columbidae/SppDataRequest.shp'
birdlife = st_read(BIRDLIFE_DISTRIBUTIONS)
Reading layer `SppDataRequest' from data source `/Users/james/Dropbox/PhD/BirdLife/Distribution/SppDataRequest_columbidae/SppDataRequest.shp' using driver `ESRI Shapefile'
Simple feature collection with 529 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -180 ymin: -55.72332 xmax: 180 ymax: 70.13647
Geodetic CRS:  WGS 84
head(birdlife)
Simple feature collection with 6 features and 16 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -180 ymin: -46.62738 xmax: 180 ymax: 65.45892
Geodetic CRS:  WGS 84
     SISID            SCI_NAME PRESENCE ORIGIN SEASONAL
1 22690059   Raphus cucullatus        5      1        1
2 22690062 Pezophaps solitaria        5      1        1
3 22690066       Columba livia        1      3        1
4 22690066       Columba livia        1      1        1
5 22690074   Columba rupestris        1      1        3
6 22690074   Columba rupestris        1      1        1
                                                                                                                                          SOURCE
1 Cheke, 1987; Hachisuka, 1953; Livezey, 1993; Owadally, 1979; Strickland and Melville, 1848; Temple, 1977 ;Roberts and Solow, 2004; Cheke, 2006
2                                                                                                     Cheke, 1987; Cowles, 1987; Hachisuka, 1953
3                                            Cramp, 1997; Rasmussen, 2004; Flint, 1984; Ding, 2001; Porter, 1996; Urban, 1986; Gibbs et al, 2001
4                                Cramp, 1997; Rasmussen, 2004; Flint, 1984; Ding, 2001; Porter, 1996; Urban, 1986; Gibbs et al, 2001; eBird 2019
5                                                                                                                          Grimmett et al., 2008
6                                       Gibbs et al., 2001; Rasmussen and Anderton, 2005; Spierenburg, 2005; Grimmett et al., 2008; Brazil, 2009
                                                                        COMPILER DATA_SENS SENS_COMM DIST_COMM TAX_COMM GENERALISD
1                                         Philip Martin (BirdLife International)         0      <NA>      <NA>     <NA>          0
2                                         Philip Martin (BirdLife International)         0      <NA>      <NA>     <NA>          0
3                                                         BirdLife International         0      <NA>      <NA>     <NA>          0
4 Lynda Donaldson (BirdLife International); Donal Smith (BirdLife International)         0      <NA>      <NA>     <NA>          0
5                                            Joe Taylor (BirdLife International)         0      <NA>      <NA>     <NA>          0
6                                            Joe Taylor (BirdLife International)         0      <NA>      <NA>     <NA>          0
                                                       CITATION YRCOMPILED YRMODIFIED VERSION                       geometry
1 BirdLife International and Handbook of the Birds of the World       2010       2016  2022.2 MULTIPOLYGON (((57.64288 -2...
2 BirdLife International and Handbook of the Birds of the World       2010       2016  2022.2 MULTIPOLYGON (((63.47229 -1...
3 BirdLife International and Handbook of the Birds of the World       2006       2016  2022.2 MULTIPOLYGON (((5.383484 53...
4 BirdLife International and Handbook of the Birds of the World       2016       2019  2022.2 MULTIPOLYGON (((88.3183 21....
5 BirdLife International and Handbook of the Birds of the World       2010       2016  2022.2 MULTIPOLYGON (((75.19348 36...
6 BirdLife International and Handbook of the Birds of the World       2010       2016  2022.2 MULTIPOLYGON (((120.8933 36...

Read in the Birdlife Taxonomy

Load the birdlife taxonomy to find Columbidae species.

The taxonomy can be downloaded here: https://datazone.birdlife.org/species/taxonomy

st_crs(birdlife)
Coordinate Reference System:
  User input: WGS 84 
  wkt:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]
BIRDLIFE_TAXONOMY = '/Users/james/Dropbox/PhD/BirdLife/Taxonomy/Handbook of the Birds of the World and BirdLife International Digital Checklist of the Birds of the World_Version_8.xlsx'
birdlifeTaxonomyWb = read_excel(BIRDLIFE_TAXONOMY)
New names:
birdlifeTaxonomyWb
names(birdlifeTaxonomyWb) <- birdlifeTaxonomyWb[2,]
birdlifeTaxonomy <- birdlifeTaxonomyWb[-2,]
birdlifeTaxonomy

Fetch all columbidae species that are not extinct and are not an invalid birdlife species.

birdlifeColumbidae = birdlifeTaxonomy[!is.na(birdlifeTaxonomy$Order) & birdlifeTaxonomy$Order == 'COLUMBIFORMES', c('SISRecID', 'Scientific name', 'Common name', 'Synonyms', '2023 IUCN Red List category')]
names(birdlifeColumbidae) = c('birdlife_id', 'species_name', 'common_name', 'synonyms', 'red_list_2023')
birdlifeColumbidae = birdlifeColumbidae[!(birdlifeColumbidae$red_list_2023 %in% c('EX', 'NR')),]
birdlifeColumbidae

Check to see if we have any missing distributions

birdlifeColumbidae[!(birdlifeColumbidae$species_name %in% birdlife$SCI_NAME),]

Store Birdlife taxonomy

write_csv(birdlifeColumbidae, filename(BIRDLIFE_WORKING_OUTPUT_DIR, 'taxonomy.csv'))
birdlifeColumbidae = read_csv(filename(BIRDLIFE_WORKING_OUTPUT_DIR, 'taxonomy.csv'))
Rows: 353 Columns: 5── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): species_name, common_name, synonyms, red_list_2023
dbl (1): birdlife_id
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(birdlifeColumbidae)

Filter Birdlife Distributions to only Columbidae

Do we have any distributions not in our taxonomy, are are not extinct?

birdlife[!(birdlife$SCI_NAME %in% birdlifeColumbidae$species_name) & birdlife$PRESENCE != 5,]
Simple feature collection with 0 features and 16 fields
Bounding box:  xmin: NA ymin: NA xmax: NA ymax: NA
Geodetic CRS:  WGS 84
 [1] SISID      SCI_NAME   PRESENCE   ORIGIN     SEASONAL   SOURCE     COMPILER   DATA_SENS  SENS_COMM  DIST_COMM  TAX_COMM   GENERALISD CITATION   YRCOMPILED
[15] YRMODIFIED VERSION    geometry  
<0 rows> (or 0-length row.names)
COLUMBIDAE_WORLD_DISTRIBUTIONS = filename(BIRDLIFE_WORKING_OUTPUT_DIR, "columbidae_world.shp")
write_sf(birdlife[birdlife$PRESENCE != 5,], COLUMBIDAE_WORLD_DISTRIBUTIONS)
Warning: GDAL Message 1: Value 154619350 of field SISID of feature 491 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 154619546 of field SISID of feature 492 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 154625310 of field SISID of feature 493 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 154625453 of field SISID of feature 494 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 154625942 of field SISID of feature 495 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 200093329 of field SISID of feature 496 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 200094385 of field SISID of feature 497 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 219582631 of field SISID of feature 498 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 232609896 of field SISID of feature 499 not successfully written. Possibly due to too larger number with respect to field widthWarning: GDAL Message 1: Value 232610475 of field SISID of feature 500 not successfully written. Possibly due to too larger number with respect to field width
columbidaeDistribution = read_sf(COLUMBIDAE_WORLD_DISTRIBUTIONS)

Free up memory by removing birdlife data from workspace

rm(birdlife)
rm(birdlifeTaxonomy)
rm(birdlifeTaxonomy_tmp)
Warning: object 'birdlifeTaxonomy_tmp' not found
rm(birdlifeTaxonomyWb)
rm(birdlifeTaxonomyWb_Sheets)
Warning: object 'birdlifeTaxonomyWb_Sheets' not found
st_crs(columbidaeDistribution)
Coordinate Reference System:
  User input: WGS 84 
  wkt:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]

Create intersection of Columbidae Distributions with Urban Spaces

Read in our initial city vectors, we will join these to our checklists

initial_city_selection = read_sf(filename(mkdir(GEO_WORKING_OUTPUT_DIR, 'cities'), 'initial_selection.shp'))
st_crs(initial_city_selection)
Coordinate Reference System:
  User input: WGS 84 
  wkt:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]
sf::sf_use_s2(FALSE)
Spherical geometry (s2) switched off
urban_columbidae_distributions = st_join(initial_city_selection, columbidaeDistribution) 
although coordinates are longitude/latitude, st_intersects assumes that they are planar
urban_columbidae_distributions
Simple feature collection with 6595 features and 20 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -158.043 ymin: -38.20685 xmax: 174.9891 ymax: 60.3276
Geodetic CRS:  WGS 84

Check birdlife distribution data

Species with unknown presence?

urban_columbidae_distributions[urban_columbidae_distributions$PRESENCE > 5, c('SCI_NAME', 'city_name', 'city_id')]
Simple feature collection with 1 feature and 3 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: 116.0291 ymin: -8.698981 xmax: 116.27 ymax: -8.479668
Geodetic CRS:  WGS 84

Possibly Extinct species

urban_columbidae_distributions[urban_columbidae_distributions$PRESENCE == 4, c('SCI_NAME', 'city_name', 'city_id')]
Simple feature collection with 40 features and 3 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -82.49902 ymin: -25.60243 xmax: 125.6809 ymax: 23.18014
Geodetic CRS:  WGS 84

Map seasonal and origin to string values

urban_columbidae_distributions$seasonal_desc = "Unknown Code"
urban_columbidae_distributions$seasonal_desc[urban_columbidae_distributions$SEASONAL == "1"] = "Resident"
urban_columbidae_distributions$seasonal_desc[urban_columbidae_distributions$SEASONAL == "2"] = "Breeding Season" 
urban_columbidae_distributions$seasonal_desc[urban_columbidae_distributions$SEASONAL == "3"] = "Non-breeding Season" 
urban_columbidae_distributions$seasonal_desc[urban_columbidae_distributions$SEASONAL == "4"] = "Passage" 
urban_columbidae_distributions$seasonal_desc[urban_columbidae_distributions$SEASONAL == "5"] = "Seasonal occurence uncertain"
urban_columbidae_distributions$origin_desc = "Unknown Code"
urban_columbidae_distributions$origin_desc[urban_columbidae_distributions$ORIGIN == "1"] = "Native"
urban_columbidae_distributions$origin_desc[urban_columbidae_distributions$ORIGIN == "2"] = "Reintroduced" 
urban_columbidae_distributions$origin_desc[urban_columbidae_distributions$ORIGIN == "3"] = "Introduced" 
urban_columbidae_distributions$origin_desc[urban_columbidae_distributions$ORIGIN == "4"] = "Vagrant" 
urban_columbidae_distributions$origin_desc[urban_columbidae_distributions$ORIGIN == "5"] = "Origin Uncertain"
urban_columbidae_distributions$origin_desc[urban_columbidae_distributions$ORIGIN == "6"] = "Assisted Colonisation"
urban_columbidae_distributions$presence_desc = "Unknown Code"
urban_columbidae_distributions$presence_desc[urban_columbidae_distributions$PRESENCE == "1"] = "Extant"
urban_columbidae_distributions$presence_desc[urban_columbidae_distributions$PRESENCE == "2"] = "Probably Extant" 
urban_columbidae_distributions$presence_desc[urban_columbidae_distributions$PRESENCE == "3"] = "Possibly Extant" 
urban_columbidae_distributions$presence_desc[urban_columbidae_distributions$PRESENCE == "4"] = "Possibly Extinct" 
urban_columbidae_distributions$presence_desc[urban_columbidae_distributions$PRESENCE == "5"] = "Extinct"
urban_columbidae_distributions$presence_desc[urban_columbidae_distributions$PRESENCE == "6"] = "Presence Uncertain"
cache_urban_columbidae_distributions = filename(BIRDLIFE_WORKING_OUTPUT_DIR, 'urban_distributions_birdlife_only.csv')
write_csv(urban_columbidae_distributions, cache_urban_columbidae_distributions)
urban_columbidae_distributions = read_csv(cache_urban_columbidae_distributions)
Rows: 6595 Columns: 24── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (11): city_name, geometry, SCI_NAME, SOURCE, COMPILER, DIST_COMM, TAX_COMM, CITATION, seasonal_desc, origin_desc, presence_desc
dbl (12): city_id, pop_2015, bu_2015, SISID, PRESENCE, ORIGIN, SEASONAL, DATA_SENS, GENERALISD, YRCOMPILED, YRMODIFIED, VERSION
lgl  (1): SENS_COMM
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Missing North American distribution of Streptopelia decaocto and Columba Livia

Birdlife is missing the recent invasion of Streptopelia decaocto into North America. We supplement the data for Streptopelia decaocto with the range from eBird’s Status and Trends dataset.

This data can be downloaded here: https://science.ebird.org/en/status-and-trends/species/eucdov/downloads

The country boundandaries can be downloaded from the world bank here: https://datacatalog.worldbank.org/search/dataset/0038272/World-Bank-Official-Boundaries

COUNTRY_BOUNDARIES = '/Users/james/Dropbox/PhD/WorldBank_countries_Admin0_10m/WB_countries_Admin0_10m.shp'
world_map = st_simplify(st_read(COUNTRY_BOUNDARIES), dTolerance = 0.02)
Reading layer `WB_countries_Admin0_10m' from data source `/Users/james/Dropbox/PhD/WorldBank_countries_Admin0_10m/WB_countries_Admin0_10m.shp' using driver `ESRI Shapefile'
Simple feature collection with 251 features and 52 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -180 ymin: -59.47275 xmax: 180 ymax: 83.6341
Geodetic CRS:  WGS 84
Warning: st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees

Collared Dove

Existing range from Birdlife

sf::sf_use_s2(FALSE)
coldov_vect = st_simplify(columbidaeDistribution[columbidaeDistribution$SCI_NAME == 'Streptopelia decaocto', c('PRESENCE')], dTolerance = 0.02)
Warning: st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees
ggplot() +  
  geom_sf(data = world_map, aes(geometry = geometry)) +
  geom_sf(data = coldov_vect, aes(geometry = geometry), fill = "red")

Range from eBird

EBIRD_EUCDOV_RANGE = '/Users/james/Dropbox/PhD/eBird/eucdov_range_2022/eucdov_range_2022.gpkg'
eucdov_range_vect = st_read(EBIRD_EUCDOV_RANGE)
Reading layer `range' from data source `/Users/james/Dropbox/PhD/eBird/eucdov_range_2022/eucdov_range_2022.gpkg' using driver `GPKG'
Simple feature collection with 1 feature and 8 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -129.1392 ymin: 6.847467 xmax: 128.6997 ymax: 60.44009
Geodetic CRS:  WGS 84
ggplot() +  
  geom_sf(data = world_map, aes(geometry = geometry)) +
  geom_sf(data = eucdov_range_vect["scientific_name"], aes(geometry = geom), fill = "red")

Extract cities from eBird range

sf::sf_use_s2(FALSE)

existing_eucdov_cities = urban_columbidae_distributions$city_id[urban_columbidae_distributions$SCI_NAME == 'Streptopelia decaocto']

eucdov_distribution = st_join(initial_city_selection, eucdov_range_vect) 
although coordinates are longitude/latitude, st_intersects assumes that they are planar
eucdov_distribution[!is.na(eucdov_distribution$species_code) & !(eucdov_distribution$city_id %in% existing_eucdov_cities),]
Simple feature collection with 116 features and 12 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -123.2852 ymin: 16.69475 xmax: 126.8399 ymax: 51.22359
Geodetic CRS:  WGS 84
missing_eucdov_cities = data.frame(
    species_name = 'Streptopelia decaocto', 
    city_id = eucdov_distribution$city_id[!is.na(eucdov_distribution$species_code) & !(eucdov_distribution$city_id %in% existing_eucdov_cities)],
    city_name= eucdov_distribution$city_name[!is.na(eucdov_distribution$species_code) & !(eucdov_distribution$city_id %in% existing_eucdov_cities)],
    origin = 'Introduced',
    seasonal = 'Resident',
    presence = 'Extant'
)
missing_eucdov_cities

Rock dove

Existing range from Birdlife

sf::sf_use_s2(FALSE)
rocdov_vect = st_simplify(columbidaeDistribution[columbidaeDistribution$SCI_NAME == 'Columba livia', c('PRESENCE')], dTolerance = 0.02)
Warning: st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees
ggplot() +  
  geom_sf(data = world_map, aes(geometry = geometry)) +
  geom_sf(data = rocdov_vect, aes(geometry = geometry), fill = "red")

Range from eBird

EBIRD_ROCPIG_RANGE = '/Users/james/Dropbox/PhD/eBird/rocpig_range_2022/rocpig_range_2022.gpkg'
rocpig_range_vect = st_read(EBIRD_ROCPIG_RANGE)
Reading layer `range' from data source `/Users/james/Dropbox/PhD/eBird/rocpig_range_2022/rocpig_range_2022.gpkg' using driver `GPKG'
Simple feature collection with 1 feature and 8 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -159.9356 ymin: -53.31565 xmax: 178.8437 ymax: 69.31292
Geodetic CRS:  WGS 84
ggplot() +  
  geom_sf(data = world_map, aes(geometry = geometry)) +
  geom_sf(data = rocpig_range_vect["scientific_name"], aes(geometry = geom), fill = "red")

sf::sf_use_s2(FALSE)

existing_rocpig_cities = urban_columbidae_distributions$city_id[urban_columbidae_distributions$SCI_NAME == 'Columba livia']

rocpig_distribution = st_join(initial_city_selection, rocpig_range_vect) 
although coordinates are longitude/latitude, st_intersects assumes that they are planar
rocpig_distribution[!is.na(rocpig_distribution$species_code) & !(rocpig_distribution$city_id %in% existing_rocpig_cities),]
Simple feature collection with 453 features and 12 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -158.043 ymin: -38.11825 xmax: 141.5939 ymax: 53.66794
Geodetic CRS:  WGS 84
missing_rocpig_cities = data.frame(
    species_name = 'Columba livia', 
    city_id = rocpig_distribution$city_id[!is.na(rocpig_distribution$species_code) & !(rocpig_distribution$city_id %in% existing_rocpig_cities)],
    city_name= rocpig_distribution$city_name[!is.na(rocpig_distribution$species_code) & !(rocpig_distribution$city_id %in% existing_rocpig_cities)],
    origin = 'Introduced',
    seasonal = 'Resident',
    presence = 'Extant'
)
missing_rocpig_cities

Add Spotted dove’s expanded range into China

Existing range from Birdlife

sf::sf_use_s2(FALSE)
spodov_vect = st_simplify(columbidaeDistribution[columbidaeDistribution$SCI_NAME %in% c('Spilopelia chinensis','Spilopelia suratensis','Patagioenas albipennis'), c('SCI_NAME')], dTolerance = 0.02)
Warning: st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees
ggplot() +  
  geom_sf(data = world_map, aes(geometry = geometry)) +
  geom_sf(data = spodov_vect, aes(geometry = geometry, fill = SCI_NAME))

Range from eBird

EBIRD_SPODOV_RANGE = '/Users/james/Dropbox/PhD/eBird/spodov_range_2022/spodov_range_2022.gpkg'
spodov_range_vect = st_read(EBIRD_SPODOV_RANGE)
Reading layer `range' from data source `/Users/james/Dropbox/PhD/eBird/spodov_range_2022/spodov_range_2022.gpkg' using driver `GPKG'
Simple feature collection with 1 feature and 8 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -180 ymin: -43.72339 xmax: 180 ymax: 44.8739
Geodetic CRS:  WGS 84
ggplot() +  
  geom_sf(data = world_map, aes(geometry = geometry)) +
  geom_sf(data = spodov_range_vect["scientific_name"], aes(geometry = geom), fill = "red")

sf::sf_use_s2(FALSE)

existing_spodov_cities = urban_columbidae_distributions$city_id[urban_columbidae_distributions$SCI_NAME %in% c('Spilopelia chinensis','Spilopelia suratensis','Patagioenas albipennis')]

spodov_distribution = st_join(initial_city_selection, spodov_range_vect) 
although coordinates are longitude/latitude, st_intersects assumes that they are planar
spodov_distribution[!is.na(spodov_distribution$species_code) & !(spodov_distribution$city_id %in% existing_spodov_cities),]
Simple feature collection with 29 features and 12 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: 70.54817 ymin: 27.96718 xmax: 125.8892 ymax: 43.98709
Geodetic CRS:  WGS 84
missing_spodov_cities = data.frame(
    species_name = 'Spilopelia chinensis', 
    city_id = spodov_distribution$city_id[!is.na(spodov_distribution$species_code) & !(spodov_distribution$city_id %in% existing_spodov_cities)],
    city_name= spodov_distribution$city_name[!is.na(spodov_distribution$species_code) & !(spodov_distribution$city_id %in% existing_spodov_cities)],
    origin = 'Introduced',
    seasonal = 'Resident',
    presence = 'Extant'
)
missing_spodov_cities

Store regional pool result

urban_distribution = rbind(
  data.frame(
    species_name = urban_columbidae_distributions$SCI_NAME, 
    city_id = urban_columbidae_distributions$city_id,
    city_name= urban_columbidae_distributions$city_name,
    origin = urban_columbidae_distributions$origin_desc,
    seasonal = urban_columbidae_distributions$seasonal_desc,
    presence = urban_columbidae_distributions$presence_desc
  ),
 rbind(missing_eucdov_cities, rbind(missing_rocpig_cities, missing_spodov_cities))
)
BIRDLIFE_URBAN_DISTRIBUTION = filename(BIRDLIFE_WORKING_OUTPUT_DIR, 'urban_distributions.csv')
write_csv(urban_distribution, BIRDLIFE_URBAN_DISTRIBUTION)

Examine result

urban_distribution = read_csv(BIRDLIFE_URBAN_DISTRIBUTION)
Rows: 7193 Columns: 6── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): species_name, city_name, origin, seasonal, presence
dbl (1): city_id
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Species in Manchester’s regional pool

urban_distribution %>% filter(city_name == 'Manchester') 

Species in Miami’s regional pool

urban_distribution %>% filter(city_name == 'Miami') 

Cities with Common Woodpigeon in regional pool

urban_distribution %>% filter(species_name == 'Columba palumbus')

Cities with Collared Dove in regional pool

urban_distribution %>% filter(species_name == 'Streptopelia decaocto')

Regional pool sizes

urban_distribution %>% group_by(city_id, city_name) %>% summarise(pool_size = n()) %>% arrange(pool_size)
`summarise()` has grouped output by 'city_id'. You can override using the `.groups` argument.
“Bird Species Distribution Maps of the World.” 2020. BirdLife International; Handbook of the Birds of the World. http://datazone.birdlife.org/species/requestdis.
LS0tCnRpdGxlOiAiQ3JlYXRlIHJlZ2lvbmFsIHBvb2xzIHVzaW5nIEJpcmRMaWZlIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYmlibGlvZ3JhcGh5OiAuLi9yZWYuYmliIAotLS0KCmBgYHtyfQpzb3VyY2UoJy4uL2Vudi5SJykKYGBgCgojIEdlbmVyYXRlIFdvcmxkd2lkZSBEaXN0cmlidXRpb25zIGZvciBhbGwgQ29sdW1iaWRhZQoKIyMgUmVhZCBpbiB0aGUgQmlyZGxpZmUgRGlzdHJpYnV0aW9uIApCaXJkbGlmZSBkYXRhc2V0IEBCaXJkbGlmZTIwMjAuCgpBIGRvd25sb2FkIG9mIHRoZSBiaXJkbGlmZSBkaXN0cmlidXRpb25zIGNhbiBiZSByZXF1ZXN0ZWQgZnJvbSBoZXJlOgpodHRwczovL2RhdGF6b25lLmJpcmRsaWZlLm9yZy9zcGVjaWVzL3JlcXVlc3RkaXMKCmBgYHtyfQpCSVJETElGRV9ESVNUUklCVVRJT05TID0gJy9Vc2Vycy9qYW1lcy9Ecm9wYm94L1BoRC9CaXJkTGlmZS9EaXN0cmlidXRpb24vU3BwRGF0YVJlcXVlc3RfY29sdW1iaWRhZS9TcHBEYXRhUmVxdWVzdC5zaHAnCmJpcmRsaWZlID0gc3RfcmVhZChCSVJETElGRV9ESVNUUklCVVRJT05TKQpoZWFkKGJpcmRsaWZlKQpgYGAKCiMjIFJlYWQgaW4gdGhlIEJpcmRsaWZlIFRheG9ub215CkxvYWQgdGhlIGJpcmRsaWZlIHRheG9ub215IHRvIGZpbmQgQ29sdW1iaWRhZSBzcGVjaWVzLgoKVGhlIHRheG9ub215IGNhbiBiZSBkb3dubG9hZGVkIGhlcmU6Cmh0dHBzOi8vZGF0YXpvbmUuYmlyZGxpZmUub3JnL3NwZWNpZXMvdGF4b25vbXkKCmBgYHtyfQpzdF9jcnMoYmlyZGxpZmUpCmBgYAoKYGBge3J9CkJJUkRMSUZFX1RBWE9OT01ZID0gJy9Vc2Vycy9qYW1lcy9Ecm9wYm94L1BoRC9CaXJkTGlmZS9UYXhvbm9teS9IYW5kYm9vayBvZiB0aGUgQmlyZHMgb2YgdGhlIFdvcmxkIGFuZCBCaXJkTGlmZSBJbnRlcm5hdGlvbmFsIERpZ2l0YWwgQ2hlY2tsaXN0IG9mIHRoZSBCaXJkcyBvZiB0aGUgV29ybGRfVmVyc2lvbl84Lnhsc3gnCmJpcmRsaWZlVGF4b25vbXlXYiA9IHJlYWRfZXhjZWwoQklSRExJRkVfVEFYT05PTVkpCmJpcmRsaWZlVGF4b25vbXlXYgpgYGAKCmBgYHtyfQpuYW1lcyhiaXJkbGlmZVRheG9ub215V2IpIDwtIGJpcmRsaWZlVGF4b25vbXlXYlsyLF0KYmlyZGxpZmVUYXhvbm9teSA8LSBiaXJkbGlmZVRheG9ub215V2JbLTIsXQpiaXJkbGlmZVRheG9ub215CmBgYApGZXRjaCBhbGwgY29sdW1iaWRhZSBzcGVjaWVzIHRoYXQgYXJlIG5vdCBleHRpbmN0IGFuZCBhcmUgbm90IGFuIGludmFsaWQgYmlyZGxpZmUgc3BlY2llcy4KYGBge3J9CmJpcmRsaWZlQ29sdW1iaWRhZSA9IGJpcmRsaWZlVGF4b25vbXlbIWlzLm5hKGJpcmRsaWZlVGF4b25vbXkkT3JkZXIpICYgYmlyZGxpZmVUYXhvbm9teSRPcmRlciA9PSAnQ09MVU1CSUZPUk1FUycsIGMoJ1NJU1JlY0lEJywgJ1NjaWVudGlmaWMgbmFtZScsICdDb21tb24gbmFtZScsICdTeW5vbnltcycsICcyMDIzIElVQ04gUmVkIExpc3QgY2F0ZWdvcnknKV0KbmFtZXMoYmlyZGxpZmVDb2x1bWJpZGFlKSA9IGMoJ2JpcmRsaWZlX2lkJywgJ3NwZWNpZXNfbmFtZScsICdjb21tb25fbmFtZScsICdzeW5vbnltcycsICdyZWRfbGlzdF8yMDIzJykKYmlyZGxpZmVDb2x1bWJpZGFlID0gYmlyZGxpZmVDb2x1bWJpZGFlWyEoYmlyZGxpZmVDb2x1bWJpZGFlJHJlZF9saXN0XzIwMjMgJWluJSBjKCdFWCcsICdOUicpKSxdCmJpcmRsaWZlQ29sdW1iaWRhZQpgYGAKCkNoZWNrIHRvIHNlZSBpZiB3ZSBoYXZlIGFueSBtaXNzaW5nIGRpc3RyaWJ1dGlvbnMKYGBge3J9CmJpcmRsaWZlQ29sdW1iaWRhZVshKGJpcmRsaWZlQ29sdW1iaWRhZSRzcGVjaWVzX25hbWUgJWluJSBiaXJkbGlmZSRTQ0lfTkFNRSksXQpgYGAKCiMjIFN0b3JlIEJpcmRsaWZlIHRheG9ub215CmBgYHtyfQp3cml0ZV9jc3YoYmlyZGxpZmVDb2x1bWJpZGFlLCBmaWxlbmFtZShCSVJETElGRV9XT1JLSU5HX09VVFBVVF9ESVIsICd0YXhvbm9teS5jc3YnKSkKYmlyZGxpZmVDb2x1bWJpZGFlID0gcmVhZF9jc3YoZmlsZW5hbWUoQklSRExJRkVfV09SS0lOR19PVVRQVVRfRElSLCAndGF4b25vbXkuY3N2JykpCmhlYWQoYmlyZGxpZmVDb2x1bWJpZGFlKQpgYGAKCiMjIEZpbHRlciBCaXJkbGlmZSBEaXN0cmlidXRpb25zIHRvIG9ubHkgQ29sdW1iaWRhZQpEbyB3ZSBoYXZlIGFueSBkaXN0cmlidXRpb25zIG5vdCBpbiBvdXIgdGF4b25vbXksIGFyZSBhcmUgbm90IGV4dGluY3Q/CmBgYHtyfQpiaXJkbGlmZVshKGJpcmRsaWZlJFNDSV9OQU1FICVpbiUgYmlyZGxpZmVDb2x1bWJpZGFlJHNwZWNpZXNfbmFtZSkgJiBiaXJkbGlmZSRQUkVTRU5DRSAhPSA1LF0KYGBgCgpgYGB7cn0KQ09MVU1CSURBRV9XT1JMRF9ESVNUUklCVVRJT05TID0gZmlsZW5hbWUoQklSRExJRkVfV09SS0lOR19PVVRQVVRfRElSLCAiY29sdW1iaWRhZV93b3JsZC5zaHAiKQp3cml0ZV9zZihiaXJkbGlmZVtiaXJkbGlmZSRQUkVTRU5DRSAhPSA1LF0sIENPTFVNQklEQUVfV09STERfRElTVFJJQlVUSU9OUykKY29sdW1iaWRhZURpc3RyaWJ1dGlvbiA9IHJlYWRfc2YoQ09MVU1CSURBRV9XT1JMRF9ESVNUUklCVVRJT05TKQpgYGAKCgpGcmVlIHVwIG1lbW9yeSBieSByZW1vdmluZyBiaXJkbGlmZSBkYXRhIGZyb20gd29ya3NwYWNlCmBgYHtyfQpybShiaXJkbGlmZSkKcm0oYmlyZGxpZmVUYXhvbm9teSkKcm0oYmlyZGxpZmVUYXhvbm9teV90bXApCnJtKGJpcmRsaWZlVGF4b25vbXlXYikKcm0oYmlyZGxpZmVUYXhvbm9teVdiX1NoZWV0cykKYGBgCgpgYGB7cn0Kc3RfY3JzKGNvbHVtYmlkYWVEaXN0cmlidXRpb24pCmBgYAoKIyBDcmVhdGUgaW50ZXJzZWN0aW9uIG9mIENvbHVtYmlkYWUgRGlzdHJpYnV0aW9ucyB3aXRoIFVyYmFuIFNwYWNlcwpSZWFkIGluIG91ciBpbml0aWFsIGNpdHkgdmVjdG9ycywgd2Ugd2lsbCBqb2luIHRoZXNlIHRvIG91ciBjaGVja2xpc3RzCmBgYHtyfQppbml0aWFsX2NpdHlfc2VsZWN0aW9uID0gcmVhZF9zZihmaWxlbmFtZShta2RpcihHRU9fV09SS0lOR19PVVRQVVRfRElSLCAnY2l0aWVzJyksICdpbml0aWFsX3NlbGVjdGlvbi5zaHAnKSkKYGBgCgpgYGB7cn0Kc3RfY3JzKGluaXRpYWxfY2l0eV9zZWxlY3Rpb24pCmBgYAoKYGBge3J9CnNmOjpzZl91c2VfczIoRkFMU0UpCgp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMgPSBzdF9qb2luKGluaXRpYWxfY2l0eV9zZWxlY3Rpb24sIGNvbHVtYmlkYWVEaXN0cmlidXRpb24pIAoKdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zCmBgYAoKIyMgQ2hlY2sgYmlyZGxpZmUgZGlzdHJpYnV0aW9uIGRhdGEKClNwZWNpZXMgd2l0aCB1bmtub3duIHByZXNlbmNlPwpgYGB7cn0KdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zW3VyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRQUkVTRU5DRSA+IDUsIGMoJ1NDSV9OQU1FJywgJ2NpdHlfbmFtZScsICdjaXR5X2lkJyldCmBgYAoKCgpQb3NzaWJseSBFeHRpbmN0IHNwZWNpZXMKYGBge3J9CnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9uc1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkUFJFU0VOQ0UgPT0gNCwgYygnU0NJX05BTUUnLCAnY2l0eV9uYW1lJywgJ2NpdHlfaWQnKV0KYGBgCgojIyBNYXAgc2Vhc29uYWwgYW5kIG9yaWdpbiB0byBzdHJpbmcgdmFsdWVzCmBgYHtyfQp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkc2Vhc29uYWxfZGVzYyA9ICJVbmtub3duIENvZGUiCnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRzZWFzb25hbF9kZXNjW3VyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRTRUFTT05BTCA9PSAiMSJdID0gIlJlc2lkZW50Igp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkc2Vhc29uYWxfZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkU0VBU09OQUwgPT0gIjIiXSA9ICJCcmVlZGluZyBTZWFzb24iIAp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkc2Vhc29uYWxfZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkU0VBU09OQUwgPT0gIjMiXSA9ICJOb24tYnJlZWRpbmcgU2Vhc29uIiAKdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJHNlYXNvbmFsX2Rlc2NbdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJFNFQVNPTkFMID09ICI0Il0gPSAiUGFzc2FnZSIgCnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRzZWFzb25hbF9kZXNjW3VyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRTRUFTT05BTCA9PSAiNSJdID0gIlNlYXNvbmFsIG9jY3VyZW5jZSB1bmNlcnRhaW4iCmBgYAoKYGBge3J9CnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRvcmlnaW5fZGVzYyA9ICJVbmtub3duIENvZGUiCnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRvcmlnaW5fZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkT1JJR0lOID09ICIxIl0gPSAiTmF0aXZlIgp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkb3JpZ2luX2Rlc2NbdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJE9SSUdJTiA9PSAiMiJdID0gIlJlaW50cm9kdWNlZCIgCnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRvcmlnaW5fZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkT1JJR0lOID09ICIzIl0gPSAiSW50cm9kdWNlZCIgCnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRvcmlnaW5fZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkT1JJR0lOID09ICI0Il0gPSAiVmFncmFudCIgCnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRvcmlnaW5fZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkT1JJR0lOID09ICI1Il0gPSAiT3JpZ2luIFVuY2VydGFpbiIKdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJG9yaWdpbl9kZXNjW3VyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRPUklHSU4gPT0gIjYiXSA9ICJBc3Npc3RlZCBDb2xvbmlzYXRpb24iCmBgYAoKYGBge3J9CnVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRwcmVzZW5jZV9kZXNjID0gIlVua25vd24gQ29kZSIKdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJHByZXNlbmNlX2Rlc2NbdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJFBSRVNFTkNFID09ICIxIl0gPSAiRXh0YW50Igp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkcHJlc2VuY2VfZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkUFJFU0VOQ0UgPT0gIjIiXSA9ICJQcm9iYWJseSBFeHRhbnQiIAp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkcHJlc2VuY2VfZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkUFJFU0VOQ0UgPT0gIjMiXSA9ICJQb3NzaWJseSBFeHRhbnQiIAp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkcHJlc2VuY2VfZGVzY1t1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkUFJFU0VOQ0UgPT0gIjQiXSA9ICJQb3NzaWJseSBFeHRpbmN0IiAKdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJHByZXNlbmNlX2Rlc2NbdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJFBSRVNFTkNFID09ICI1Il0gPSAiRXh0aW5jdCIKdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJHByZXNlbmNlX2Rlc2NbdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJFBSRVNFTkNFID09ICI2Il0gPSAiUHJlc2VuY2UgVW5jZXJ0YWluIgpgYGAKCmBgYHtyfQpjYWNoZV91cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMgPSBmaWxlbmFtZShCSVJETElGRV9XT1JLSU5HX09VVFBVVF9ESVIsICd1cmJhbl9kaXN0cmlidXRpb25zX2JpcmRsaWZlX29ubHkuY3N2JykKd3JpdGVfY3N2KHVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucywgY2FjaGVfdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zKQp1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMgPSByZWFkX2NzdihjYWNoZV91cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMpCmBgYAoKIyMgTWlzc2luZyBOb3J0aCBBbWVyaWNhbiBkaXN0cmlidXRpb24gb2YgU3RyZXB0b3BlbGlhIGRlY2FvY3RvIGFuZCBDb2x1bWJhIExpdmlhCkJpcmRsaWZlIGlzIG1pc3NpbmcgdGhlIHJlY2VudCBpbnZhc2lvbiBvZiBTdHJlcHRvcGVsaWEgZGVjYW9jdG8gaW50byBOb3J0aCBBbWVyaWNhLiAKV2Ugc3VwcGxlbWVudCB0aGUgZGF0YSBmb3IgU3RyZXB0b3BlbGlhIGRlY2FvY3RvIHdpdGggdGhlIHJhbmdlIGZyb20gZUJpcmQncyBTdGF0dXMgYW5kIFRyZW5kcyBkYXRhc2V0LgoKVGhpcyBkYXRhIGNhbiBiZSBkb3dubG9hZGVkIGhlcmU6Cmh0dHBzOi8vc2NpZW5jZS5lYmlyZC5vcmcvZW4vc3RhdHVzLWFuZC10cmVuZHMvc3BlY2llcy9ldWNkb3YvZG93bmxvYWRzCgpUaGUgY291bnRyeSBib3VuZGFuZGFyaWVzIGNhbiBiZSBkb3dubG9hZGVkIGZyb20gdGhlIHdvcmxkIGJhbmsgaGVyZToKaHR0cHM6Ly9kYXRhY2F0YWxvZy53b3JsZGJhbmsub3JnL3NlYXJjaC9kYXRhc2V0LzAwMzgyNzIvV29ybGQtQmFuay1PZmZpY2lhbC1Cb3VuZGFyaWVzCgpgYGB7cn0KQ09VTlRSWV9CT1VOREFSSUVTID0gJy9Vc2Vycy9qYW1lcy9Ecm9wYm94L1BoRC9Xb3JsZEJhbmtfY291bnRyaWVzX0FkbWluMF8xMG0vV0JfY291bnRyaWVzX0FkbWluMF8xMG0uc2hwJwp3b3JsZF9tYXAgPSBzdF9zaW1wbGlmeShzdF9yZWFkKENPVU5UUllfQk9VTkRBUklFUyksIGRUb2xlcmFuY2UgPSAwLjAyKQpgYGAKIyMjIENvbGxhcmVkIERvdmUKRXhpc3RpbmcgcmFuZ2UgZnJvbSBCaXJkbGlmZQpgYGB7cn0Kc2Y6OnNmX3VzZV9zMihGQUxTRSkKY29sZG92X3ZlY3QgPSBzdF9zaW1wbGlmeShjb2x1bWJpZGFlRGlzdHJpYnV0aW9uW2NvbHVtYmlkYWVEaXN0cmlidXRpb24kU0NJX05BTUUgPT0gJ1N0cmVwdG9wZWxpYSBkZWNhb2N0bycsIGMoJ1BSRVNFTkNFJyldLCBkVG9sZXJhbmNlID0gMC4wMikKCmdncGxvdCgpICsgIAogIGdlb21fc2YoZGF0YSA9IHdvcmxkX21hcCwgYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpKSArCiAgZ2VvbV9zZihkYXRhID0gY29sZG92X3ZlY3QsIGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgZmlsbCA9ICJyZWQiKQpgYGAKClJhbmdlIGZyb20gZUJpcmQKYGBge3J9CkVCSVJEX0VVQ0RPVl9SQU5HRSA9ICcvVXNlcnMvamFtZXMvRHJvcGJveC9QaEQvZUJpcmQvZXVjZG92X3JhbmdlXzIwMjIvZXVjZG92X3JhbmdlXzIwMjIuZ3BrZycKZXVjZG92X3JhbmdlX3ZlY3QgPSBzdF9yZWFkKEVCSVJEX0VVQ0RPVl9SQU5HRSkKCmdncGxvdCgpICsgIAogIGdlb21fc2YoZGF0YSA9IHdvcmxkX21hcCwgYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpKSArCiAgZ2VvbV9zZihkYXRhID0gZXVjZG92X3JhbmdlX3ZlY3RbInNjaWVudGlmaWNfbmFtZSJdLCBhZXMoZ2VvbWV0cnkgPSBnZW9tKSwgZmlsbCA9ICJyZWQiKQpgYGAKCkV4dHJhY3QgY2l0aWVzIGZyb20gZUJpcmQgcmFuZ2UKYGBge3J9CnNmOjpzZl91c2VfczIoRkFMU0UpCgpleGlzdGluZ19ldWNkb3ZfY2l0aWVzID0gdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJGNpdHlfaWRbdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJFNDSV9OQU1FID09ICdTdHJlcHRvcGVsaWEgZGVjYW9jdG8nXQoKZXVjZG92X2Rpc3RyaWJ1dGlvbiA9IHN0X2pvaW4oaW5pdGlhbF9jaXR5X3NlbGVjdGlvbiwgZXVjZG92X3JhbmdlX3ZlY3QpIAoKZXVjZG92X2Rpc3RyaWJ1dGlvblshaXMubmEoZXVjZG92X2Rpc3RyaWJ1dGlvbiRzcGVjaWVzX2NvZGUpICYgIShldWNkb3ZfZGlzdHJpYnV0aW9uJGNpdHlfaWQgJWluJSBleGlzdGluZ19ldWNkb3ZfY2l0aWVzKSxdCmBgYAoKCmBgYHtyfQptaXNzaW5nX2V1Y2Rvdl9jaXRpZXMgPSBkYXRhLmZyYW1lKAogICAgc3BlY2llc19uYW1lID0gJ1N0cmVwdG9wZWxpYSBkZWNhb2N0bycsIAogICAgY2l0eV9pZCA9IGV1Y2Rvdl9kaXN0cmlidXRpb24kY2l0eV9pZFshaXMubmEoZXVjZG92X2Rpc3RyaWJ1dGlvbiRzcGVjaWVzX2NvZGUpICYgIShldWNkb3ZfZGlzdHJpYnV0aW9uJGNpdHlfaWQgJWluJSBleGlzdGluZ19ldWNkb3ZfY2l0aWVzKV0sCiAgICBjaXR5X25hbWU9IGV1Y2Rvdl9kaXN0cmlidXRpb24kY2l0eV9uYW1lWyFpcy5uYShldWNkb3ZfZGlzdHJpYnV0aW9uJHNwZWNpZXNfY29kZSkgJiAhKGV1Y2Rvdl9kaXN0cmlidXRpb24kY2l0eV9pZCAlaW4lIGV4aXN0aW5nX2V1Y2Rvdl9jaXRpZXMpXSwKICAgIG9yaWdpbiA9ICdJbnRyb2R1Y2VkJywKICAgIHNlYXNvbmFsID0gJ1Jlc2lkZW50JywKICAgIHByZXNlbmNlID0gJ0V4dGFudCcKKQptaXNzaW5nX2V1Y2Rvdl9jaXRpZXMKYGBgCgojIyMgUm9jayBkb3ZlCkV4aXN0aW5nIHJhbmdlIGZyb20gQmlyZGxpZmUKYGBge3J9CnNmOjpzZl91c2VfczIoRkFMU0UpCnJvY2Rvdl92ZWN0ID0gc3Rfc2ltcGxpZnkoY29sdW1iaWRhZURpc3RyaWJ1dGlvbltjb2x1bWJpZGFlRGlzdHJpYnV0aW9uJFNDSV9OQU1FID09ICdDb2x1bWJhIGxpdmlhJywgYygnUFJFU0VOQ0UnKV0sIGRUb2xlcmFuY2UgPSAwLjAyKQoKZ2dwbG90KCkgKyAgCiAgZ2VvbV9zZihkYXRhID0gd29ybGRfbWFwLCBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSkpICsKICBnZW9tX3NmKGRhdGEgPSByb2Nkb3ZfdmVjdCwgYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBmaWxsID0gInJlZCIpCmBgYAoKUmFuZ2UgZnJvbSBlQmlyZApgYGB7cn0KRUJJUkRfUk9DUElHX1JBTkdFID0gJy9Vc2Vycy9qYW1lcy9Ecm9wYm94L1BoRC9lQmlyZC9yb2NwaWdfcmFuZ2VfMjAyMi9yb2NwaWdfcmFuZ2VfMjAyMi5ncGtnJwpyb2NwaWdfcmFuZ2VfdmVjdCA9IHN0X3JlYWQoRUJJUkRfUk9DUElHX1JBTkdFKQpnZ3Bsb3QoKSArICAKICBnZW9tX3NmKGRhdGEgPSB3b3JsZF9tYXAsIGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSkgKwogIGdlb21fc2YoZGF0YSA9IHJvY3BpZ19yYW5nZV92ZWN0WyJzY2llbnRpZmljX25hbWUiXSwgYWVzKGdlb21ldHJ5ID0gZ2VvbSksIGZpbGwgPSAicmVkIikKYGBgCgpgYGB7cn0Kc2Y6OnNmX3VzZV9zMihGQUxTRSkKCmV4aXN0aW5nX3JvY3BpZ19jaXRpZXMgPSB1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkY2l0eV9pZFt1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkU0NJX05BTUUgPT0gJ0NvbHVtYmEgbGl2aWEnXQoKcm9jcGlnX2Rpc3RyaWJ1dGlvbiA9IHN0X2pvaW4oaW5pdGlhbF9jaXR5X3NlbGVjdGlvbiwgcm9jcGlnX3JhbmdlX3ZlY3QpIAoKcm9jcGlnX2Rpc3RyaWJ1dGlvblshaXMubmEocm9jcGlnX2Rpc3RyaWJ1dGlvbiRzcGVjaWVzX2NvZGUpICYgIShyb2NwaWdfZGlzdHJpYnV0aW9uJGNpdHlfaWQgJWluJSBleGlzdGluZ19yb2NwaWdfY2l0aWVzKSxdCmBgYAoKYGBge3J9Cm1pc3Npbmdfcm9jcGlnX2NpdGllcyA9IGRhdGEuZnJhbWUoCiAgICBzcGVjaWVzX25hbWUgPSAnQ29sdW1iYSBsaXZpYScsIAogICAgY2l0eV9pZCA9IHJvY3BpZ19kaXN0cmlidXRpb24kY2l0eV9pZFshaXMubmEocm9jcGlnX2Rpc3RyaWJ1dGlvbiRzcGVjaWVzX2NvZGUpICYgIShyb2NwaWdfZGlzdHJpYnV0aW9uJGNpdHlfaWQgJWluJSBleGlzdGluZ19yb2NwaWdfY2l0aWVzKV0sCiAgICBjaXR5X25hbWU9IHJvY3BpZ19kaXN0cmlidXRpb24kY2l0eV9uYW1lWyFpcy5uYShyb2NwaWdfZGlzdHJpYnV0aW9uJHNwZWNpZXNfY29kZSkgJiAhKHJvY3BpZ19kaXN0cmlidXRpb24kY2l0eV9pZCAlaW4lIGV4aXN0aW5nX3JvY3BpZ19jaXRpZXMpXSwKICAgIG9yaWdpbiA9ICdJbnRyb2R1Y2VkJywKICAgIHNlYXNvbmFsID0gJ1Jlc2lkZW50JywKICAgIHByZXNlbmNlID0gJ0V4dGFudCcKKQptaXNzaW5nX3JvY3BpZ19jaXRpZXMKYGBgCgojIyBBZGQgU3BvdHRlZCBkb3ZlJ3MgZXhwYW5kZWQgcmFuZ2UgaW50byBDaGluYQpFeGlzdGluZyByYW5nZSBmcm9tIEJpcmRsaWZlCmBgYHtyfQpzZjo6c2ZfdXNlX3MyKEZBTFNFKQpzcG9kb3ZfdmVjdCA9IHN0X3NpbXBsaWZ5KGNvbHVtYmlkYWVEaXN0cmlidXRpb25bY29sdW1iaWRhZURpc3RyaWJ1dGlvbiRTQ0lfTkFNRSAlaW4lIGMoJ1NwaWxvcGVsaWEgY2hpbmVuc2lzJywnU3BpbG9wZWxpYSBzdXJhdGVuc2lzJywnUGF0YWdpb2VuYXMgYWxiaXBlbm5pcycpLCBjKCdTQ0lfTkFNRScpXSwgZFRvbGVyYW5jZSA9IDAuMDIpCgpnZ3Bsb3QoKSArICAKICBnZW9tX3NmKGRhdGEgPSB3b3JsZF9tYXAsIGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSkgKwogIGdlb21fc2YoZGF0YSA9IHNwb2Rvdl92ZWN0LCBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSwgZmlsbCA9IFNDSV9OQU1FKSkKYGBgCgpSYW5nZSBmcm9tIGVCaXJkCmBgYHtyfQpFQklSRF9TUE9ET1ZfUkFOR0UgPSAnL1VzZXJzL2phbWVzL0Ryb3Bib3gvUGhEL2VCaXJkL3Nwb2Rvdl9yYW5nZV8yMDIyL3Nwb2Rvdl9yYW5nZV8yMDIyLmdwa2cnCnNwb2Rvdl9yYW5nZV92ZWN0ID0gc3RfcmVhZChFQklSRF9TUE9ET1ZfUkFOR0UpCmdncGxvdCgpICsgIAogIGdlb21fc2YoZGF0YSA9IHdvcmxkX21hcCwgYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpKSArCiAgZ2VvbV9zZihkYXRhID0gc3BvZG92X3JhbmdlX3ZlY3RbInNjaWVudGlmaWNfbmFtZSJdLCBhZXMoZ2VvbWV0cnkgPSBnZW9tKSwgZmlsbCA9ICJyZWQiKQpgYGAKCmBgYHtyfQpzZjo6c2ZfdXNlX3MyKEZBTFNFKQoKZXhpc3Rpbmdfc3BvZG92X2NpdGllcyA9IHVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRjaXR5X2lkW3VyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRTQ0lfTkFNRSAlaW4lIGMoJ1NwaWxvcGVsaWEgY2hpbmVuc2lzJywnU3BpbG9wZWxpYSBzdXJhdGVuc2lzJywnUGF0YWdpb2VuYXMgYWxiaXBlbm5pcycpXQoKc3BvZG92X2Rpc3RyaWJ1dGlvbiA9IHN0X2pvaW4oaW5pdGlhbF9jaXR5X3NlbGVjdGlvbiwgc3BvZG92X3JhbmdlX3ZlY3QpIAoKc3BvZG92X2Rpc3RyaWJ1dGlvblshaXMubmEoc3BvZG92X2Rpc3RyaWJ1dGlvbiRzcGVjaWVzX2NvZGUpICYgIShzcG9kb3ZfZGlzdHJpYnV0aW9uJGNpdHlfaWQgJWluJSBleGlzdGluZ19zcG9kb3ZfY2l0aWVzKSxdCmBgYAoKYGBge3J9Cm1pc3Npbmdfc3BvZG92X2NpdGllcyA9IGRhdGEuZnJhbWUoCiAgICBzcGVjaWVzX25hbWUgPSAnU3BpbG9wZWxpYSBjaGluZW5zaXMnLCAKICAgIGNpdHlfaWQgPSBzcG9kb3ZfZGlzdHJpYnV0aW9uJGNpdHlfaWRbIWlzLm5hKHNwb2Rvdl9kaXN0cmlidXRpb24kc3BlY2llc19jb2RlKSAmICEoc3BvZG92X2Rpc3RyaWJ1dGlvbiRjaXR5X2lkICVpbiUgZXhpc3Rpbmdfc3BvZG92X2NpdGllcyldLAogICAgY2l0eV9uYW1lPSBzcG9kb3ZfZGlzdHJpYnV0aW9uJGNpdHlfbmFtZVshaXMubmEoc3BvZG92X2Rpc3RyaWJ1dGlvbiRzcGVjaWVzX2NvZGUpICYgIShzcG9kb3ZfZGlzdHJpYnV0aW9uJGNpdHlfaWQgJWluJSBleGlzdGluZ19zcG9kb3ZfY2l0aWVzKV0sCiAgICBvcmlnaW4gPSAnSW50cm9kdWNlZCcsCiAgICBzZWFzb25hbCA9ICdSZXNpZGVudCcsCiAgICBwcmVzZW5jZSA9ICdFeHRhbnQnCikKbWlzc2luZ19zcG9kb3ZfY2l0aWVzCmBgYAoKIyMgU3RvcmUgcmVnaW9uYWwgcG9vbCByZXN1bHQKYGBge3J9CnVyYmFuX2Rpc3RyaWJ1dGlvbiA9IHJiaW5kKAogIGRhdGEuZnJhbWUoCiAgICBzcGVjaWVzX25hbWUgPSB1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkU0NJX05BTUUsIAogICAgY2l0eV9pZCA9IHVyYmFuX2NvbHVtYmlkYWVfZGlzdHJpYnV0aW9ucyRjaXR5X2lkLAogICAgY2l0eV9uYW1lPSB1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkY2l0eV9uYW1lLAogICAgb3JpZ2luID0gdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJG9yaWdpbl9kZXNjLAogICAgc2Vhc29uYWwgPSB1cmJhbl9jb2x1bWJpZGFlX2Rpc3RyaWJ1dGlvbnMkc2Vhc29uYWxfZGVzYywKICAgIHByZXNlbmNlID0gdXJiYW5fY29sdW1iaWRhZV9kaXN0cmlidXRpb25zJHByZXNlbmNlX2Rlc2MKICApLAogcmJpbmQobWlzc2luZ19ldWNkb3ZfY2l0aWVzLCByYmluZChtaXNzaW5nX3JvY3BpZ19jaXRpZXMsIG1pc3Npbmdfc3BvZG92X2NpdGllcykpCikKYGBgCgpgYGB7cn0KQklSRExJRkVfVVJCQU5fRElTVFJJQlVUSU9OID0gZmlsZW5hbWUoQklSRExJRkVfV09SS0lOR19PVVRQVVRfRElSLCAndXJiYW5fZGlzdHJpYnV0aW9ucy5jc3YnKQp3cml0ZV9jc3YodXJiYW5fZGlzdHJpYnV0aW9uLCBCSVJETElGRV9VUkJBTl9ESVNUUklCVVRJT04pCmBgYAoKIyMgRXhhbWluZSByZXN1bHQKYGBge3J9CnVyYmFuX2Rpc3RyaWJ1dGlvbiA9IHJlYWRfY3N2KEJJUkRMSUZFX1VSQkFOX0RJU1RSSUJVVElPTikKYGBgCgpTcGVjaWVzIGluIE1hbmNoZXN0ZXIncyByZWdpb25hbCBwb29sCmBgYHtyfQp1cmJhbl9kaXN0cmlidXRpb24gJT4lIGZpbHRlcihjaXR5X25hbWUgPT0gJ01hbmNoZXN0ZXInKSAKYGBgCgpTcGVjaWVzIGluIE1pYW1pJ3MgcmVnaW9uYWwgcG9vbApgYGB7cn0KdXJiYW5fZGlzdHJpYnV0aW9uICU+JSBmaWx0ZXIoY2l0eV9uYW1lID09ICdNaWFtaScpIApgYGAKCkNpdGllcyB3aXRoIENvbW1vbiBXb29kcGlnZW9uIGluIHJlZ2lvbmFsIHBvb2wKYGBge3J9CnVyYmFuX2Rpc3RyaWJ1dGlvbiAlPiUgZmlsdGVyKHNwZWNpZXNfbmFtZSA9PSAnQ29sdW1iYSBwYWx1bWJ1cycpCmBgYAoKQ2l0aWVzIHdpdGggQ29sbGFyZWQgRG92ZSBpbiByZWdpb25hbCBwb29sCmBgYHtyfQp1cmJhbl9kaXN0cmlidXRpb24gJT4lIGZpbHRlcihzcGVjaWVzX25hbWUgPT0gJ1N0cmVwdG9wZWxpYSBkZWNhb2N0bycpCmBgYAoKUmVnaW9uYWwgcG9vbCBzaXplcwpgYGB7cn0KdXJiYW5fZGlzdHJpYnV0aW9uICU+JSBncm91cF9ieShjaXR5X2lkLCBjaXR5X25hbWUpICU+JSBzdW1tYXJpc2UocG9vbF9zaXplID0gbigpKSAlPiUgYXJyYW5nZShwb29sX3NpemUpCmBgYAoK